package enum

import (
	"errors"
	"gitee.com/worklz/yunj-blog-go-micro-common/util"
	"reflect"
	"sort"
	"strings"
)

type EnumInterface[T comparable] interface {
	AllConstAttrs() map[T]map[string]any
	GetValue() T
	GetAttrMap(key string) map[T]any
	GetDescMap() map[T]string
	GetAttr(attr string) any
	GetStrAttr(attr string) string
	GetDesc() string
	GetColor() string
	GetSortConsts() []T
	GetCommaSepConstStr() string
	IsValue(value any) (val T, ok bool)
}

// Enum T 不自定义类型，防止数据库占位符?替换为字符串，在mysql进行匹配时发生类型转换
// comparable 可比较类型
type Enum[T comparable] struct {
	Value     T
	ErrPrefix string // 错误前缀
	Err       error  // 错误

	enumInstance EnumInterface[T]
}

// SetEnumInstance 设置枚举实例
func SetEnumInstance[T comparable](e *Enum[T], enumInstance EnumInterface[T], value ...T) {
	e.enumInstance = enumInstance

	// 获取指针的反射值
	enumInstanceValue := reflect.ValueOf(e.enumInstance)
	// 检查传入的是否为指针
	if enumInstanceValue.Kind() != reflect.Ptr || enumInstanceValue.IsNil() {
		e.SetError("请传入枚举实例指针值！")
	}
	// 设置值
	if len(value) > 0 {
		e.SetValue(value[0])
	}
}

// 获取构建器实例的错误前缀
func (e *Enum[T]) getErrPrefix() (prefix string, err error) {
	err = e.GetError()
	if err != nil {
		return
	}
	prefix = e.ErrPrefix
	return
}

// 设置构建器实例的错误前缀
func (e *Enum[T]) setErrPrefix(prefix string) (err error) {
	err = e.GetError()
	if err != nil {
		return
	}
	e.ErrPrefix = prefix
	return
}

// 获取枚举错误
func (e *Enum[T]) GetError() error {
	return e.Err
}

// 设置枚举错误
func (e *Enum[T]) SetError(err any) error {
	if _err := e.GetError(); _err != nil {
		return _err
	}
	var resErrMsg string
	if _errMsg, ok := err.(string); ok {
		resErrMsg = _errMsg
	} else if _err, ok := err.(error); ok {
		resErrMsg = _err.Error()
	} else {
		resErrMsg = "未知错误！"
	}

	// 错误前缀
	errPrefix, _ := e.getErrPrefix()
	if errPrefix == "" {
		typ := util.PackageFullName(e.enumInstance) + "." + util.TypeName(e.enumInstance)
		errPrefix = "枚举" + typ
		e.setErrPrefix(errPrefix)
	}

	if !strings.HasPrefix(resErrMsg, errPrefix) {
		resErrMsg = errPrefix + resErrMsg
	}
	newErr := errors.New(resErrMsg)
	e.Err = newErr
	return newErr
}

func (e *Enum[T]) GetValue() T {
	return e.Value
}

func (e *Enum[T]) SetValue(value T) {
	e.Value = value
}

// 获取所有枚举值的指定属性值
func (e *Enum[T]) GetAttrMap(key string) map[T]any {
	res := map[T]any{}
	allConstAttrs := e.enumInstance.AllConstAttrs()
	for enumVal, attrs := range allConstAttrs {
		if attr, exists := attrs[key]; exists {
			res[enumVal] = attr
		}
	}
	return res
}

// 获取所有枚举值对应的描述
func (e *Enum[T]) GetDescMap() map[T]string {
	res := map[T]string{}
	attrMap := e.GetAttrMap("desc")
	for k, v := range attrMap {
		if desc, ok := v.(string); ok {
			res[k] = desc
		}
	}
	return res
}

// 获取某一属性值
func (e *Enum[T]) GetAttr(attr string) any {
	allConstAttrs := e.enumInstance.AllConstAttrs()
	enumAttrs, exists := allConstAttrs[e.GetValue()]
	if !exists {
		return nil
	}
	attrValue, exists := enumAttrs[attr]
	if !exists {
		return nil
	}
	return attrValue
}

// 获取某一属性的字符串值
func (e *Enum[T]) GetStrAttr(attr string) string {
	raw := e.GetAttr(attr)
	res, _ := util.ToString(raw)
	return res
}

// 获取描述值
func (e *Enum[T]) GetDesc() string {
	return e.GetStrAttr("desc")
}

// 获取颜色
func (e *Enum[T]) GetColor() string {
	return e.GetStrAttr("color")
}

// 获取排序后的常量值
func (e *Enum[T]) GetSortConsts() []T {
	allConstAttrs := e.enumInstance.AllConstAttrs()

	// 提取所有的枚举值
	enumValues := make([]T, 0, len(allConstAttrs))
	enumValueSorts := map[T]int{}
	sortKeyExists := true
	for enumValue, enumAttrs := range allConstAttrs {
		enumValues = append(enumValues, enumValue)
		if sortKeyExists {
			sortRaw, exists := enumAttrs["sort"]
			if !exists {
				sortKeyExists = false
				continue
			}
			sortVal, ok := sortRaw.(int)
			if !ok {
				sortKeyExists = false
				continue
			}
			enumValueSorts[enumValue] = sortVal
		}
	}

	// 排序
	sort.Slice(enumValues, func(i, j int) bool {
		return enumValueSorts[enumValues[i]] < enumValueSorts[enumValues[j]]
	})

	return enumValues
}

// 获取逗号分隔常量的字符串值
func (e *Enum[T]) GetCommaSepConstStr() string {
	allConstAttrs := e.enumInstance.AllConstAttrs()
	var str string
	for k := range allConstAttrs {
		value, _ := util.ToString(k)
		if str != "" {
			str += "," + value
		} else {
			str = value
		}
	}
	return str
}

// 判断是否为枚举值val
func (e *Enum[T]) IsValue(value any) (val T, ok bool) {
	var err error
	if _, isUint8 := any(val).(uint8); isUint8 {
		if value, err = util.ToUint8(value); err != nil {
			return
		}
	} else if _, isUint16 := any(val).(uint16); isUint16 {
		if value, err = util.ToUint16(value); err != nil {
			return
		}
	} else if _, isUint32 := any(val).(uint32); isUint32 {
		if value, err = util.ToUint32(value); err != nil {
			return
		}
	} else if _, isStr := any(val).(string); isStr {
		if value, err = util.ToString(value); err != nil {
			return
		}
	} else if _, isInt := any(val).(int); isInt {
		if value, err = util.ToInt(value); err != nil {
			return
		}
	} else if _, isInt64 := any(val).(int64); isInt64 {
		if value, err = util.ToInt64(value); err != nil {
			return
		}
	} else {
		// 其他类型直接断言
		if _, ok = value.(T); !ok {
			return
		}
	}
	val = value.(T) // 将值转换为 T 类型
	allConstAttrs := e.enumInstance.AllConstAttrs()
	_, ok = allConstAttrs[val]
	return
}
